package com.author.surface;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;

import com.author.document.model.DocumentService;
import com.author.document.model.DocumentServiceListener;
import com.author.util.ServiceRegister;

public final class StatusBar extends JPanel implements DocumentServiceListener {
	/* Width and height of the StatusBar */
	private static int	STATUSBAR_WIDTH	= 0;
	private static int	STATUSBAR_HEIGHT = 0;

	/* Color of the StatusBar */
	private static final Color	STATUSBAR_COLOR	= Color.lightGray;

	/* Layout of StatusBar */
	private final FlowLayout layout	= new FlowLayout();
	
	/* The status bar contains three panels */
	private JPanel statusBarPanel1 = null;
	private JPanel statusbarPanel2 = null;
	private JPanel statusBarPanel3 = null;
	
	/* Status bar labels for printing document information */
	private JLabel statusBarLabel1 = null;
	private JLabel statusBarLabel2 = null;
	private JLabel statusBarLabel3 = null;
	
	/* Document Char count */
	private long docCharCount = 0;
	
	/* Display string used to display char count in the first label */
	private static final String CHAR_COUNT = "Chars: "; 
	
	/* Worker threads */
	private final Thread[] workerThreads = new Thread [] {
		new Thread (new Runnable () {
			public void run () {
				waitForUpdate ();
			}
		}),
		new Thread (new Runnable () {
			public void run () {
				waitForUpdate ();				
			}
		})		
	};
	
	/* Name of the two worker threads */
	private static final String FIRST_THREAD = "FIRST_THREAD";
	private static final String SECOND_THREAD = "SECOND_THREAD";
	
	public StatusBar(int width, int height) {
		/*
		 * The task of specifying the width and height of the status bar lies
		 * with the Application Surface.
		 */
		StatusBar.STATUSBAR_WIDTH = width;
		StatusBar.STATUSBAR_HEIGHT = height;

		setSize(new Dimension(StatusBar.STATUSBAR_WIDTH, 
				StatusBar.STATUSBAR_HEIGHT));
		setPreferredSize(getSize());
		
		// Set the layout and the color of the status bar
		setLayout(null);
		setBackground(STATUSBAR_COLOR);
		
		// Add panels inside status bar (these panels will be used to display 
		// document information such as - chars, spaces, words etc
		
		// The first panel will be currently be used to display document
		// information such as the number of characters etc.
		this.statusBarPanel1 = new JPanel ();
		this.statusBarPanel1.setSize(width / 3, height);
		this.statusBarPanel1.setBorder(BorderFactory.createLoweredBevelBorder());
		this.statusBarPanel1.setBackground(STATUSBAR_COLOR);
		
		this.statusBarLabel1 = new JLabel (CHAR_COUNT +
				String.valueOf(this.docCharCount));
		this.statusBarPanel1.setLayout(new FlowLayout());
		
		this.statusBarPanel1.add(statusBarLabel1, FlowLayout.LEFT);
		this.add(statusBarPanel1);

		// The second panel will be used to display locale information
		this.statusbarPanel2 = new JPanel ();
		this.statusbarPanel2.setSize(width / 3, height);
		this.statusbarPanel2.setLocation(width / 3, 0);
		this.statusbarPanel2.setBorder(BorderFactory.createLoweredBevelBorder());
		this.statusbarPanel2.setBackground(STATUSBAR_COLOR);
		this.add(statusbarPanel2);

		// The third panel will be used to display page and paragraph 
		// information
		this.statusBarPanel3 = new JPanel ();
		this.statusBarPanel3.setSize(width / 3, height);
		this.statusBarPanel3.setLocation((width - (width / 3)), 0);
		this.statusBarPanel3.setBorder(BorderFactory.createLoweredBevelBorder());
		this.statusBarPanel3.setBackground(STATUSBAR_COLOR);
		this.add(statusBarPanel3);
		
		// Register status bar to receive notifications from DocumentService
		// about the changes taking place in the state of the document
		ServiceRegister servReg = ServiceRegister.getServiceRegister();
		if (servReg != null) {
			try {
				servReg.registerForService(DocumentService.DOCUMENT_SERVICE,
						this);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		// Make status bar visible
		setVisible(true);
		
		// Initialize all worker threads of the component
		initWorkerThreads ();
	}

	private void initWorkerThreads() {
		if (this.workerThreads != null) {
			int count = 0;
			for (Thread thread : this.workerThreads) {
				count++;
				switch (count) {
				case 1:
					thread.setName(FIRST_THREAD);
					thread.start();
					break;
				case 2:
					thread.setName(SECOND_THREAD);
					thread.start();
					break;
				default:
					break;
				}
			}
		}
	}

	@Override
	public synchronized void update(DocumentService docService) {
		if (docService != null) {
			this.docCharCount = docService.getDocumentCharCount() <= 0 ? 0 : 
				docService.getDocumentCharCount();
			this.notifyAll();
		}
	}
	
	private synchronized void waitForUpdate() {
		while (true) {
			try {
				wait ();
			} catch (InterruptedException e) {
			}
			
			// The following code will repaint the status panel inside the status bar
			// that is responsible for showing the number of chars in the document
			String threadName = Thread.currentThread().getName();
			if (threadName.equals(FIRST_THREAD)) {
				this.statusBarLabel1.setText(CHAR_COUNT + String.valueOf(docCharCount));
				EventQueue.invokeLater(new Runnable() {
					public void run () {
						StatusBar.this.statusBarPanel1.repaint();
					}
				});
			}
		}
	}
}
